/**
 * CoffeeMilk (C) 2010 Amen Hamdan
 * 
 * See the NOTICE file distributed with this work for additional 
 * information regarding copyright ownership.  This file is licenses
 * to you under the Apache License, Version 2.0 (the "License"); you 
 * may not use this file except in compliance with the License.  You 
 * may obtain a copy of the License at
 * 
 *     http://www.apache.org/licenses/LICENSE-2.0
 *     
 * Unless required by applicable law or agreed to in writing, software 
 * distributed under the License is distributed on an "AS IS" BASIS, 
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 
 * implied. See the License for the specific language governing 
 * permissions and limitations under the License.    
 * 
 */
package ameen.rtm.lib.types;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TreeMap;
import java.util.Vector;

public class TasksVector extends Vector<RtmTask> implements PropertyChangeListener {
	private static final long serialVersionUID 		= 1846229815605885184L;
	public static final String ELEMENT_ADDED   		= "MonitoredVector.addedElement";
	public static final String ELEMENT_REMOVED 		= "MonitoredVector.removedElement";
	public static final String ADDED_ALL       		= "MonitoredVector.addedAll";
	public static final String SORTORDER_CHANGED    = "MonitoredVector.sortOrderChanged";
	public static final String TASK_UPDATED    		= "MonitoredVector.taskUpdated";

	private SortOrder fSortOrder = SortOrder.UNSORTED;
	private final PropertyChangeSupport fPropertyChangeSupport = new PropertyChangeSupport(this);
	private final SimpleDateFormat fDateFormatter = new SimpleDateFormat("yyMMddHHmmssZ");
	private final String fEmtpyDateString = "0000000000000";
	
	public enum SortOrder {
		UNSORTED,
		NAME_ASCENDING, NAME_DESCENDING, 
		PRIORITY_ASCENDING, PRIORITY_DESCENDING, 
		DUEDATE_ASCENDING, DUEDATE_DESCENDING
	}	


	public void setSortMethod(SortOrder newSortOrder) {
		if(newSortOrder == fSortOrder) return;
		
		SortOrder oldSortOrder = fSortOrder;
		fSortOrder = newSortOrder;
		sortVector();
		fPropertyChangeSupport.firePropertyChange(SORTORDER_CHANGED, oldSortOrder, fSortOrder);
	
	}
	
	
	private void sortVector() {
		if(size() == 0) return;
		
		switch (fSortOrder) {
		case NAME_ASCENDING:
			sortByNameAsc();
			break;

		case NAME_DESCENDING:
			sortByNameDesc();
			break;
			
		case PRIORITY_ASCENDING:
			sortByPrioAsc();
			break;
			
		case PRIORITY_DESCENDING:
			sortByPrioDesc();
			break;
			
		case DUEDATE_ASCENDING:
			sortByDueDateAsc();
			break;
			
		case DUEDATE_DESCENDING:
			sortByDueDateDesc();
			break;
	
		default:
			break;
		}
	}
	
	private void sortByNameAsc() {
		TreeMap<String, RtmTask> treeMap = createNameSet();
		this.clear();
		this.addAll(treeMap.values());
	}
	
	private void sortByNameDesc() {
		TreeMap<String, RtmTask> treeMap = createNameSet();
		this.clear();
		this.addAll(treeMap.descendingMap().values());
	}

	private void sortByPrioAsc() {
		TreeMap<String, RtmTask> treeMap = createPrioSet();
		this.clear();
		this.addAll(treeMap.descendingMap().values());
	}

	private void sortByPrioDesc() {
		TreeMap<String, RtmTask> treeMap = createPrioSet();
		this.clear();
		this.addAll(treeMap.values());
	}

	private void sortByDueDateAsc() {
		TreeMap<String, RtmTask> treeMap = createDueDateSet();
		this.clear();
		this.addAll(treeMap.values());
	}

	private void sortByDueDateDesc() {
		TreeMap<String, RtmTask> treeMap = createDueDateSet();
		this.clear();
		this.addAll(treeMap.descendingMap().values());
	}

	private TreeMap<String, RtmTask> createNameSet() {
		TreeMap<String, RtmTask> treeMap = new TreeMap<String, RtmTask>();
		for(RtmTask currentTask : this) {
			treeMap.put(currentTask.getName() + currentTask.getId(), currentTask);
		}
		return treeMap;
	}

	private TreeMap<String, RtmTask> createPrioSet() {
		TreeMap<String, RtmTask> treeMap = new TreeMap<String, RtmTask>();
		for(RtmTask currentTask : this) {
			String prioString = "00";
			switch(currentTask.getPriority()) {
			case(0):
				prioString = "50";
				break;
			case(1):
				prioString = "10";
				break;
			case(2):
				prioString = "20";
				break;
			case(3):
				prioString = "30";
				break;
			}
			
			treeMap.put(prioString + currentTask.getId(), currentTask);
		}
		return treeMap;
	}
	
	private TreeMap<String, RtmTask> createDueDateSet() {
		TreeMap<String, RtmTask> treeMap = new TreeMap<String, RtmTask>();
		for(RtmTask currentTask : this) {
			Date dueDate = currentTask.getDueDate();
			if(dueDate == null) {
				treeMap.put(fEmtpyDateString + currentTask.getId(), currentTask);
			} else {
				treeMap.put(fDateFormatter.format(dueDate) + currentTask.getId(), currentTask);
			}
		}
		return treeMap;
	}
	
	public void addPropertyChangeListener(PropertyChangeListener listener) {
		this.fPropertyChangeSupport.addPropertyChangeListener(listener);
	}
	
	public void removePropertyChangeListener(PropertyChangeListener listener) {
		this.fPropertyChangeSupport.removePropertyChangeListener(listener);
	}
	
	public void add(int index, RtmTask element) {
		super.add(index, element);
		sortVector();
		fPropertyChangeSupport.firePropertyChange(ELEMENT_ADDED, null, element);
	};

	public synchronized boolean add(RtmTask e) {
		boolean retVal = super.add(e);
		e.addPropertyChangeListener(this);
		sortVector();
		fPropertyChangeSupport.firePropertyChange(ELEMENT_ADDED, null, e);
		return retVal;
	};
	
	@Override
	public synchronized RtmTask remove(int index) {
		RtmTask retVal = super.remove(index);
		fPropertyChangeSupport.firePropertyChange(ELEMENT_REMOVED, retVal, null);
		return retVal;
	}
	
	@Override
	public boolean remove(Object o) {
		boolean retVal = super.remove(o);
		fPropertyChangeSupport.firePropertyChange(ELEMENT_REMOVED, o, null);
		return retVal;
	}


	@Override
	public void propertyChange(PropertyChangeEvent evt) {
		if(evt.getSource() instanceof RtmTask) {
			if( (evt.getPropertyName() == RtmTask.PRIORITY) ||  
					(evt.getPropertyName() == RtmTask.NAME) ||
					(evt.getPropertyName() == RtmTask.NEW_DUEDATE) ) {
					
				sortVector();
				fPropertyChangeSupport.firePropertyChange(TASK_UPDATED, null, this);
			}
		}
	}
	
}
